﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;

namespace ScopaSL.Gameplay
{
    public enum AIType
    {
        Human,
        Stupid,
        Smart,
        Expert
    }

    /// <summary>
    /// Un giocatore e i suoi dati
    /// </summary>
    public class Player
    {
        // LOGIC DATA
        public AIType AIType;
        //public List<int> Scores;
        public int Scores;
        public int ScopaCounter;
        public bool Carte, Denari, Settebello, Primiera, Win = false;
        //public PlayerBlock Hand;
        public List<Card> Cards; //{ get { return Hand.Cards; } set { Hand.Cards = value; } }
        public List<CardBlock> Takes;

        // RENDER DATA
        public string Name;
        public Color Color;
        public Point Position;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <param name="seed"></param>
        /// <returns></returns>
        public bool hasCard(int value, CardSeed seed)
        {
            for (int i = 0; i < Takes.Count; i++)
            {
                for (int j = 0; j < Takes[i].Cards.Count; j++)
                {
                    if (Takes[i].Cards[j].Value == value && Takes[i].Cards[j].Seed == seed) return true;
                }
            }

            return false;
        }

    }

    /// <summary>
    /// Colori delle carte
    /// </summary>
    public enum CardColor
    {
        White,
        Red,
        Green,
        Blue,
        Yellow,
        Black
    }

    /// <summary>
    /// Semi delle carte
    /// </summary>
    public enum CardSeed
    {
        Denari,
        Spade,
        Bastoni,
        Coppe
    }

    /// <summary>
    /// Una carta
    /// </summary>
    public class Card
    {
        // LOGIC DATA
        public int Value;
        public CardSeed Seed;
        public bool matchValid;

        // RENDER DATA
        public CardColor Color;
        public Rectangle SourceRectangle;
        public bool Selected;
        public Point CoordPosition;
        public int Width;
        public int Height;
        public bool IsAnimated;
        public float Depth = 0.2f;
        public bool ShowBack;
        public int NumSlot;
        public bool IsBeingDragged;
        public bool IsTurning;
        public float Rotation;
    }

    /// <summary>
    /// Un insieme di carte
    /// </summary>
    public class CardBlock
    {
        public List<Card> Cards;
        //public int PlayedByIndex;

        public bool hasCard(int v)
        {
            for (int i = 0; i < Cards.Count; i++)
                if (Cards[i].Value == v)
                    return true;

            return false;
        }
    }


    /// <summary>
    /// Carte in mano ad un giocatore
    /// </summary>
    public class PlayerBlock : CardBlock { }

    /// <summary>
    /// Il mazzo
    /// </summary>
    public class Pack : CardBlock { }

    /// <summary>
    /// Le carte estratte dal mazzo
    /// </summary>
    public class ExtractedCards : CardBlock { }

    /// <summary>
    /// Servizio di gioco che indica lo stato della partita
    /// </summary>
    public class BoardState
    {
        /// <summary>
        /// Carte sul tavolo
        /// </summary>
        public List<CardBlock> BoardBlocks = new List<CardBlock>();

        /// <summary>
        /// Giocatori
        /// </summary>
        public List<Player> Players = new List<Player>();

        /// <summary>
        /// Mazzo
        /// </summary>
        public Pack Pack = new Pack();

        /// <summary>
        /// Animazioni
        /// </summary>
        //public List<CardAnimation> Animations = new List<CardAnimation>();

        /// <summary>
        /// Parametri animazioni
        /// </summary>
        public bool MossaFatta;
        public bool MossaAnimata;

        /// <summary>
        /// Indice del giocatore corrente
        /// </summary>
        public int CurrentPlayerIndex;

        // Indica se è una partita veloce o normale
        public bool quickGame = false;

        // Indica se la partita è finita o no
        public bool endGame = false;
    }

    /// <summary>
    /// Punteggio di un giocatore per il fine partita
    /// </summary>
    public class PlayerScore
    {
        public int Score;
    }

    /// <summary>
    /// Punteggio
    /// </summary>
    public struct Score
    {
        public List<PlayerScore> PlayerScores;
    }

    public struct Combination
    {
        public List<int> cardsIndices;
    }


    /// <summary>
    /// Gestore delle entitá di gioco (carte, giocatori, turni, etc.); questo layer é molto generale, e non si
    /// occupa delle regole specifiche del gioco (e non sa come giocano i giocatori)
    /// </summary>
    public abstract class BoardLayer : ILevelManager<Score>
    {
        protected Random random;
        protected BoardState state;

        public BoardLayer(BoardState state)
            : base()
        {
            random = new Random();

            //game.Services.AddService(typeof(ILevelManager<Score>), this);
        }


        // Carte sul tavolo
        //protected List<CardBlock> blocks = new List<CardBlock>();
        // Lista di combinazioni
        protected List<Combination>[] mosse;

        // Carte nel mazzo 
        //protected Pack pack = new Pack();
        public Pack pack
        {
            get { return state.Pack; }
            set { state.Pack = value; }
        }
        // Informazioni sui giocatori
        //protected List<Player> players = new List<Player>();
        public List<Player> players
        {
            get { return state.Players; }
        }
        public List<CardBlock> blocks
        {
            get { return state.BoardBlocks; }
        }
        // Lista di animazioni
        //protected List<CardAnimation> animations = new List<CardAnimation>();
        //public List<CardAnimation> animations
        //{
        //    get { return state.Animations; }
        //}
        // Parametri delle animazioni
        //protected bool mossaFatta;
        public bool mossaFatta
        {
            get { return state.MossaFatta; }
            set { state.MossaFatta = value; }
        }
        //protected bool mossaAnimata;
        public bool mossaAnimata
        {
            get { return state.MossaAnimata; }
            set { state.MossaAnimata = value; }
        }
        // Indice del giocatore corrente
        //protected int current_player_index;
        public int current_player_index
        {
            get
            {
                return state.CurrentPlayerIndex;
            }
            protected set
            {
                state.CurrentPlayerIndex = value;
            }
        }

        protected abstract void OnTurnChanged(bool firstToPlay);
        protected void TurnOver()
        {
            state.CurrentPlayerIndex = (state.CurrentPlayerIndex + 1) % players.Count;
            OnTurnChanged(false);
        }
        public Player CurrentPlayer { get { return players[current_player_index]; } }


        //protected readonly int STARTING_CARDS = 13;
        //protected readonly int NUM_PLAYERS = 4;

        //Solitario: 3 carte iniziali, 1 solo giocatore
        protected readonly int STARTING_CARDS = 3;
        protected int NUM_PLAYERS = 2;

        protected abstract BoardState StartGame();

        protected Score score;

        public event LevelWon<Score> OnLevelWon;
        public event LevelLost OnLevelLost;

        protected void LevelWon(Score score)
        {
            if (OnLevelWon != null)
                OnLevelWon(score);
        }

        protected void LevelLost()
        {
            if (OnLevelLost != null)
                OnLevelLost();
        }
    }
}

